<html>
<head>
<title>CS61C Spring 2008 -- Project 4</title>
<style>
pre { display: inline; }
table {
  background-color: e0e0e0;
}
td {
  font-family: courier;
  padding-left: 1em;
  padding-right: 1em;
}
</style>
</head>
<body>

<center>
  <b>
    University of California at Berkeley<br>
    College of Engineering<br>
    Department of Electrical Engineering and Computer Science
  </b>

  <p>EECS 61C, Spring 2008

  <p><h2>Project 4</h2>
  <p><b><font color="#ff0000">Due Thursday, May 1, 2008 @ 11:59:59pm</font></b>
</center>

<p><b>TA in charge</b>: Keaton Mowery (<a href="mailto:kmowery@berkeley.edu">kmowery@berkeley.edu</a>)<br /></p>

<p><hr width=75%></p>

<h3>Notes/Updates</h3>
<ul>
<li>Watch this space!  If we unfortunately should need to make a change to the project spec, we will document it here.</li>
<li>We will be releasing oracles for Cygwin, OS X, and Linux soon.  The oracle will be the compiled TA solution, so that you can check your cache behavior against ours.</li>

<li>Remember to read tips.h for useful definitions! Particularly, all the variables in there are defined as extern and you can simply use these variables in cachelogic.c (i.e. the cache is already there for you, as well as other constants/enums).</li>
<li>If you're having problems with GUI speed in the 61C lab, feel free to move down the hall to the 61B lab - it should be much faster.</li>
</ul>

<p><hr width=75%></p>

<a name="intro" /><h2>Contents</h2>
<ul>
<li><a href="#intro">Brief Introduction</a></li>
<li><a href="#setup_inst">Setup on Inst Machines</a></li>
<li><a href="#GUI">GUI Walkthrough</a></li>
<li><a href="#task">Your Task</a></li>
<li><a href="#start">Getting Started</a></li>
<li><a href="#dump">Creating Dump Files for Testing</a></li>
<li><a href="#questions">Questions to Answer</a></li>
<li><a href="#submit">Submitting Your Solution</a></li>
<li><a href="#bugs">Bugs and Suggestions</a></li>
<li><a href="#FAQ">Frequently Asked Questions</a></li>
<li><a href="#setup_cygwin">Setup on Windows Machines (Cygwin)</a></li>
<li><a href="#setup_osx">Setup on OS X</a></li>
<li><a href="#setup_linux">Setup on Linux</a></li>
<li><a href="#setup_other">Setup on Other Machines</a></li>
</ul>

<p><hr width=75%></p>

<a name="intro" /><h2>Brief Introduction</h2>

	<p>This project will give you intimate knowledge of cache logic through implementation of, you guessed it, cache logic. We will be providing you a MIPS simulator called <b>TIPS</b> (Thousands of Instructions Per Second), that will be able to run MIPS instructions. However, the cache logic is broken (read: conveniently non-existant)!</p>

	<p>Your job is to implement the cache logic behind the cache so that <b>TIPS</b> can make use of the many benefits cacheing entails. You may choose to complete this project either by yourself or with <u>one</u> other partner.</p>

<p>If you choose to do this project individually, your slip days will work as normal.  However, if you choose to do this project with another person, the group's total slip days will be the average of the two team members' days, rounded down.  For example, if both partners have 2 slip days, then the team will have 2 slip days.  If one partner has 1 slip day and the other has 3, the team will have 2 slip days.</p>

<p>An oracle will be provided soon so you can compare your solution with ours.</p>

<p><hr width=75%></p>

<a name="setup_inst" /><h2>Setup on Inst Machines</h2>

<ul>
	<li>Copy the contents of ~cs61c/proj/04 to a suitable location in your home directory.<br /><br />
<table>
<tr><td>  $ cp -r ~cs61c/proj/04/ ~/proj4</td></tr>
</table><br /></li>

<li>To compile and run <b>TIPS</b>:<br /><br />
<table>
<tr><td>  $ gmake</td></tr>
<tr><td>  $ ./tips</td></tr>
</table><br /></li>

<li>As was mentioned before, the initial <b>TIPS</b> code has a default cache size of 0 since there is no cache logic present. You can configure the cache by clicking on the "Config Cache" button at the lower left of the interface. To run the oracle, run <code>tips_oracle.</code></li>
</ul>

<p><hr width=75%></p>

<a name="GUI" /><h2>GUI Walkthrough</h2>

<p>The GUI has been designed to be straight-forward. There are four main components to the GUI interface: register display, execution log, cache display, and control panel.

<p>
<table border=0 width=100% style="background-color:#fff">
<tr valign=center>
<td><img src=gui.jpg></td>
<td width=5%>&nbsp;</td>
<td style="font-family: serif">
<p>A description of each of the GUI widgets are described as follows:
<ol>
<li>Register display -- detailed view of the current state of the registers
<li>Execution log -- log of actions by <b>TIPS</b>. Messages can be displayed in this box using the <code>append_log()</code> function.
<li>Cache display -- current snapshot of the state of the cache. The meaning of the column headings on each unit are:
<ul>
<li>Blk - block number
<li>V - valid bit
<li>D - dirty bit
<li>LRU - LRU data
<li>Tag - Tag for the block
<li>Numbers (00, 04, etc.) - offset in the cache block data
</ul>
<li>Config Cache -- configure the cache parameters
<li>Load Program -- loads a dump file for execution
<li>Step -- execute one instruction
<li>Run -- automate execution
<li>CPU -- reset the PC and reinitialize registers
<li>Cache -- flush the cache
<li>Output -- clear the execution log
<li>Quit -- exit <b>TIPS</b>
</ol>
</td>
</tr>
</table>

<p>There is also a text-based version of the GUI for those who prefer it. You can access it with the following call:
<pre>
  $ ./tips -nogui
</pre>
<p>Type help at the TIPS prompt to get a list of commands usable in this mode.

<p><hr width=75%></p>

<a name="task" /><h2>Your Task</h2>

<p>To complete this project, you must complete the <code>accessMemory()</code> function in <code>cachelogic.c</code>. This function will handle accessing actual memory, using the <code>accessDRAM()</code> function. Thus, the behavior of <code>accessMemory()</code> function will be a cache that will call the <code>accessDRAM()</code> function as needed.</p>

<p>To ensure a variety of caches can be simulated, you will be required to dynamically support 5 properties:</p>
<ul>
<li>Associativity (ranges from 1 to 5)</li>
<li>Number of unique indexes (2<sup>n</sup> where n ranges from 0 to 4)</li>
<li>Block size (2<sup>n</sup> bytes where n ranges from 2 to 5)</li>
<li>Replacement Policy (LRU and Random)</li>
<li>Memory Synchronization Policy (Write Back and Write Through)</li>
</ul>

<p>More information about the variables you will be working with and the functions at your disposal can be ascertained by looking over <code>tips.h</code>.</p>

<p>You should keep the following things in mind when formulating the code:</p>

<ul>
<li><code>accessDRAM()</code> requires a <code>byte</code> pointer when it is called.</li>
<li>There are 4 bytes in 1 word.</li>
<li>The tag information must be right aligned. For example, if the tag is only 25 bits for a given cache configuration, the top 7 bits must always be 0.</li>
<li>When you are moving things between cache and physical memory, a <b>BLOCK</b> is transfered, <b>NOT</b> just a word nor a byte. Thus, if the block size is 16 bytes, when you want to move data from cache to memory (or vice versa) you must make sure 16 bytes travel between the cache and physical memory on your <code>accessDRAM()</code> function call.</li>
<li>Write Through policy requires the <b>ENTIRE</b> block be transferred to physical memory on a write operation.</li>
<li>To move data to and from a cache block, the <code>memcpy()</code> function should be used. The function prototype of <codE>memcpy()</code> is defined as follows:<br /><br />
<center><pre>void* memcpy(void* dest, void* src, size_t amount);</pre></center>
<p>where <code>dest</code> is the destination pointer, <code>src</code> is the memory to be copied, and <code>amount</code> is the number of bytes to copy. A more detailed description of this function can be found in K&R.</li>
</ul>

<p><hr width=75%>

<a name="start" /><h2>Getting Started</h2>

<p>Look over <code>tips.h</code> and <code>cachelogic.c</code>. <code>tips.h</code> gives you an overview of how the cache simulator is put together. A section of that file has been marked as important, so read it to get an idea of what functions and variables you will be using. <code>cachelogic.c</code> contains a slightly more detailed explanation of what you will be writing in the <code>accessMemory()</code> function.

<p>The cache data structure is divided into three levels:
<ul>
<li>The first level of entry is selecting which set you want. For example, <code>cache[2]</code> states that you are going to be accessing the 3rd set of the cache. This level is regulated by <code>set_count</code>.
<li>The next level is selecting the block you want in the set. That is specified by the <code>block</code> field. For example, <code>cache[2].block[5]</code> accesses the 6th block of the 3rd set. In the block is the tag, valid bit, dirty bit, and lru information. This level is regulated by the associativity of the cache.
<li>The final level of entry is selecting which bytes of the block do you want retrieve or modify. The data contained in a block is represented by the <code>data</code> field of that block. Using the offset, a particular byte can be referenced.
</ul>

<p>There are two methods to access the LRU information of a block. The first method is via <code>lru.value</code>, a field that will hold LRU information in integer format. The other method is via <code>lru.data</code>, a field that will hold LRU information represented in another format (its type is void*, which means it can be a pointer to anything). You are free to use either method to represent the LRU information, so long as the LRU behaves in a deterministic fashion (i.e. no two valid blocks will ever be candidates for replacement at the same time).

<p><center><img src="block_diagram.jpg"><br>
<i>Organization of the memory functions in TIPS</i>
</center>

<p>In a nutshell, the <code>accessMemory()</code> function is a function that acts as a communication layer between the CPU and DRAM. The code within the <code>accessMemory()</code> function manipulates the cache data structure defined in <code>tips.h</code>.

<p><b>All your code <u>MUST</u> be contained in cachelogic.c</b> - specifically in accessMemory() and possibly the LRU functions (depending on how you implement the LRU algorithm). You may add helper functions as long as you do not modify any code outside of cachelogic.c. Do not change any file other than cachelogic.c. Do not change the prototypes of existing functions. Just to be clear, modify only the <i>body</i> of the given functions, adding helper functions if needed.</p>

<p><hr width=75%>

<a name="dump" /><h2>Creating Dump Files for Testing</h2>

<p><b>TIPS</b> contains a subset of the MIPS R2000 processor instruction set. As a result, it accepts MIPS code assembled into binary.  The dump file can be loaded into the program by clicking on the "Load Program" button.</p>

<p>Dump files can be created in several ways.  If you are working on the inst machines, you can use the script included in the project files:</p>
<pre>
	./assemble_mips input.s output.dump
</pre>

<p>Working from home is a bit trickier, but still perfectly doable.  First, download Mars 3.4.1 from <a href="http://courses.missouristate.edu/KenVollmar/MARS/">here</a>.  Once you have the jar file, you have two options.  If you prefer to use the GUI, go ahead and start Mars and open your assembly file.  Ensure that the "Delayed Branching" setting is <b>enabled</b> in the Settings menu.  Now, assemble the source file.  Then, select the "Dump Memory" option from the File menu.  Ensure that the ".text" memory segment is selected and that the dump format is Binary, and you should be good to go.  If you prefer to use the command line, you can do something like this:</p>
<pre>
	java -jar Mars-3.4.jar a db dump .text Binary output.dump input.s
</pre>

<p><hr width=75%></p>

<a name="questions" /><h2>Questions to Answer</h2>
	<p>Answer the following questions in the README file.  You can safely assume that all associative caches in these questions use an LRU replacement policy.</p>

	<h3>Question 1:</h3>
	<p>For this question, assume 1KiB of addressable memory, 64B of L1 cache with 8B blocks. You will probably find it useful to draw the cache as you work through this problem.</p>

	<p>The code in question:</p>
<pre>
	#define ARRAY_SIZE 64<br />
	int total = 0;<br />
	char * array = malloc(ARRAY_SIZE * sizeof(char));      /* Line 1 */    // Note: chars are 1-byte wide<br />
	for(int x = 0; x < ARRAY_SIZE; x++) array[x] = x;      /* Line 2 */<br />
	for(int x = 0; x < ARRAY_SIZE; x++) total += array[x]; /* Line 3 */<br />
	for(int x = 0; x < ARRAY_SIZE; x++) total += array[x]; /* Line 4 */
</pre>

<p>a.       Assume the cache is direct-mapped and array is a pointer to the memory at offset 0b1001111000, what is the ratio of cache hits to cache misses while Line 4 is being executed?</p>

<p>b.      Assume the cache is fully associative and array is a pointer to the memory at offset 0b1001111000, what is the ratio of cache hits to cache misses while Line 4 is being executed?</p>

<p>c.       Assume the cache is direct-mapped and array is a pointer to the memory at offset 0b1001111101, what is the ratio of cache hits to cache misses while Line 4 is being executed?</p>

<p>d.      Assume the cache is fully associative and array is a pointer to the memory at offset 0b1001111101, what is the ratio of cache hits to cache misses while Line 4 is being executed?</p>

<p>e.       Do these results surprise you?  Why or why not?  Explain what's going on.  What would happen if the cache were 2-way set associative?  4-way?</p>

	<h3>Question 2:</h3>
	<p>Describe a situation in which a 2-way set associative cache would out-perform a fully associative cache.  Vice-versa?  You should describe these situations in relation to the attributes of the cache.  (i.e. accesses are made to fill every block of the cache, hitting memory block-size apart each time...)  Otherwise, the examples can be as contrived as you wish.</p>

	<h3>Question 3:</h3>
	<p>Explain the differences between write-through and write-back caches, and when/why one might be preferred over the other.</p>

	<h3>Question 4:</h3>
	<p>Suppose for a moment that virtual memory was included in this project.  How would you expect the input to accessMemory() to change?  (in other words, what type of information should the cache now receive in order to do its thing?)  <b>YOU ARE NOT EXPECTED TO IMPLEMENT THIS.</b></p>

	<h3>Question 5:</h3>
	<p>Briefly describe the changes you would have to make to your implementations in this project to implement an L2 cache.  Assume you're given a second cache struct.  How would your L1 cache implementation change?  How, if at all, would your L2 cache implementation need to be different from your original cache implementation?  <b>YOU ARE NOT EXPECTED TO IMPLEMENT THIS.</b></p>

<p><hr width=75%></p>

<a name="submit" /><h2>Submitting Your Solution</h2>

<p>Repeated for emphasis: <b>All your code <u>MUST</u> be contained in cachelogic.c (this is the only code you submit)</b></p>
<p>In testing your project, we will use all of our own files (including the Makefile) EXCEPT for your submitted cachelogic.c.</p>

<p>A README file should be submitted with your answers to the questions above and anything the grader should know reader about your project.</p>

<p>Only one person per group will need to submit; the submission process will ask for your partner's login. If both members of the group submits, the last submission will be the one we grade.</p>

<p><hr width=75%></p>

<a name="bugs" /><h2>Bugs and Suggestions</h2>
<p>
If you think you have found a bug in the <b>TIPS</b> GUI/oracle/code, please let the staff (i.e. the TA in charge) know via email or the newsgroup. Likewise, feel free to let us know of any suggestions you have. Bugs and suggestions will be addressed in updated files for this project if necessary.
</p>

<p><hr width=75%></p>

<a name="FAQ" /><h2>Frequently Asked Questions</h2>

<p><b>Q: What are the definitions of associativity and set?</b><br>
A: Associativity is the number of cache blocks that a given memory block <u>can</u> be placed using the memory block's index.

<p>Set is the collection of blocks associated with the <u>SAME</u> index. The number of unique indexes is equal to the number of sets you have.

<p><b>Q: Is an oracle available for my home computer?</b><br>
A: Oracles will be forthcoming for Cygwin/Windows, OS X, and Linux in the next few days.

<p><b>Q: I am updating the cache in my function, but the GUI isn't doing anything. What is going on?</b><br>
A: The GUI needs to be informed when changes are made to the cache. The GUI functions at your disposal are mentioned in <code>tips.h</code>.

<p><b>Q: How much of the GUI behavior do I have to copy?</b><br>
A: You will only be graded on your implementation of the cache logic in <code>cachelogic.c</code>.  You do not have to include the GUI update function calls if you don't want to, but they will help you visually understand how caching works.

<p><b>Q: Should I follow the LRU algorithm seen in COD?</b><br>
A: No, you should not follow the LRU algorithm in COD. The LRU algorithm in COD is an approximation LRU algorithm, which produces ties between valid blocks that are candidates for replacement. As a result, it is suggested you should use a true LRU algorithm, where there is a unique ranking between valid blocks. In other words, there should never be any randomness in your LRU replacement policy, nor should it always default to kicking just one block out in the event of a "tie" (two LRU values being the same for two valid blocks -- blocks with valid bit set to 1).

<p><b>Q: Do I have to use numbers for my LRU algorithm?</b><br>
A: No, you do not have to use numbers for your LRU algorithm. If you want to use something else (such as time structs), use <code>lru.data</code> as the pointer to this data. Make sure you update the <code>init_lru()</code> function and the <code>lru_to_string()</code> function.

<p><b>Q: Are the addresses in this project byte addressed or word addressed?</b><br>
A: They are byte addressed.

<p><b>Q: What do you mean by unit of transfer between cache and physical memory is in blocks?</b><br>
A: This means if you have blocks in your cache with a size of 4 words, you must always move data to and from physical memory in units of 4 words. There should never be a time in which the amount of data you move to physical memory from cache be less or greater than the block size of the cache.

<p><b>Q: Can I add more files to the project?</b><br>
A: You can, but we will not be able to test your solution in the autograder.  We will ignore all files you submit except for cachelogic.c (and the README, of course).  Do NOT put any code needed by your cachelogic.c (including header files and such) in any external file. If that's not clear, edit only cachelogic.c please -- your grade will appreciate not being a 0.

<p><b>Q: Can I work from home without the GUI?</b><br>
A: Yes, there is a "No GUI" mode for <b>TIPS</b> that can be activated by adding the <code>-nogui</code> flag on the command line when starting <b>TIPS</b>. For instructions, type "help" on the prompt after starting up <b>TIPS</b>.

<p><b>Q: Can I work from home without using SSH?</b><br>
A: Yes, the Makefile in the <code>proj4</code> folder will allow compilation on Cygwin/Windows, OS X, and Linux automatically.

<p><b>Q: Can I start <b>TIPS</b> with a dump file already loaded?</b><br>
A: Yes, <b>TIPS</b> will interpret the last argument on the command line as a name of a file. If you want to start up <b>TIPS</b> with a dump file named <code>test23.dump</code>, you can type the following:

<pre>
  % ./tips test23.dump
</pre>

<p><b>Q: I typed in <code>make</code> and it says there is an error in the Makefile. What's wrong?</b><br>
A: Use <code>gmake</code>

<p><b>Q: I ran gmake and I can't compile this project on Cygwin/Windows because of *some reason*. What do I have to do to get it to compile on Cygwin/Windows?</b><br>
A: This project's GUI interface is built on <a href="http://www.gtk.org">GTK+</a>. Compiling this project on Cygwin/Windows requires you at least install the packages mentioned in "Setup on Windows Machines (Cygwin)." Information about specifics of the general GTK+ installation can be found <a href="http://developer.gnome.org/doc/API/2.0/gtk/gtk-building.html">here</a>.

<p><b>Q: Can I use other compilers on Windows?</b><br>
A: All the project files are configured for use on Sparc/Solaris or Cygwin/Windows. If you want to use other compilers (i.e. Microsoft Visual Studio), you will have to find the libraries usable with those compilers and make the appropriate modifications. Remember, you must make sure your program compiles on the lab computers in 271 Soda.

<p><hr width=75%></p>

<a name="setup_cygwin" /><h2>Setup on Windows Machines (Cygwin)</h2>

<ul>
	<li>If you have a Cygwin install already, make sure to run setup.exe again and verify that the required packages below are installed.</li>
	<li>Download <a href="http://www.cygwin.com/setup.exe">http://www.cygwin.com/setup.exe</a> and run setup.exe. If you've already installed Cygwin, it is perfectly safe to rerun the setup to download additional packages for this project.</li>
	<li>Accept all the defaults and pick a mirror, i.e. ftp://mirrors.dotsrc.org, and select the following packages in the following <b>&lt;&lt;Categories&gt;&gt;</b><br /><br />
	<table>
		<tr>
			<td valign="top">
	<b>&lt;&lt;X11&gt;&gt;</b><br />
	xorg-x11-devel<br />
	xterm<br /><br />

	<b>&lt;&lt;Devel&gt;&gt;</b><br />
	gcc<br />
	gdb<br />
	gtk2-x11-devel<br />
	make<br />
	pango-devel<br />
	pkg-config<br />
	</td><td valign="top">
	<b>&lt;&lt;Editors&gt;&gt;</b><br />
	emacs (or vim, if you're masochistic)<br /><br />

	<b>&lt;&lt;GNOME&gt;&gt;</b><br />
	atk-devel<br /><br />

	<b>&lt;&lt;Net&gt;&gt;</b><br />
	openssh<br /><br />
	
	<b>&lt;&lt;Games&gt;&gt;</b><br />
	Just kidding =P
</td></tr></table><br /></li>
	<li>Selecting these packages will automatically select other packages required -- Do NOT uncheck these!</li>
	<li>Finish setup, run Cygwin Bash Shell once to make sure it works.</li>
	<li>Manually make a shortcut to Cygwin with X by browsing to C:\Cygwin\usr\X11R6\bin and dragging and dropping startxwin.bat with the right click button to your desktop.</li>
	<li>Download <a href="http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/1.10/ttf-bitstream-vera-1.10.tar.gz">ttf-bitstream-vera-1.10.tar.gz</a> and put it in C:\Cygwin\home\<i>your_user_name</i></li>
	<li>Run startxwin.bat (from that shortcut) and type the following:<br /><br />
<table>
<tr><td>  $ mkpasswd -l > /etc/passwd</td></tr>
<tr><td>  $ mkgroup -l > /etc/group</td></tr>
<tr><td>  $ mkdir /usr/share/fonts</td></tr>
<tr><td>  $ cd /usr/share/fonts</td></tr>
<tr><td>  $ tar xvzf ~/ttf-bitstream-vera-1.10.tar.gz</td></tr>
</table><br /></li>
<li>Should startxwin.bat not work (if you have any difficulties running Cygwin, starting multiple xterms, resource unavailable and fork() fails - specifically on Vista), Start&gt;Run and run "cmd". Make sure that before you run this command, quit ALL Cygwin windows and processes (Ctrl+Shift+Esc, kill Xwin.exe, and others). Then in the command prompt:<br /><br />
<table>
<tr><td>  C:\Users\You>C:\Cygwin\bin\ash</td></tr>
<tr><td>  $ /bin/rebaseall</td></tr>
</table><br />
</li>
<li>Get Project 4 stuff, where XX below is your login:<br /><br />
<table>
<tr><td>  $ scp -r cs61c-XX@pulsar.cs.berkeley.edu:/home/ff/cs61c/proj/04/ ~/proj4</td></tr>
<tr><td>  $ cd ~/proj4</td></tr>
<tr><td>  $ make</td></tr>
<tr><td>  $ ./tips</td></tr>
</table><br /></li>	
<li>Note that in Cygwin, you use make, not gmake, and tips_oracle_cygwin to start the oracle.</li>
</ul>

<p><hr width=75%></p>

<a name="setup_osx"><h2>Setup on OS X</h2>
<p>Leopard users: Go download <a href="http://developer.apple.com/tools/xcode/">XCode 3.0</a> from Apple's site.  You'll have to register as a developer, but accounts are free.  After downloading the 1.1GB XCode dmg, open it and install XCode.  Then, continue with installing MacPorts below.</p>

<p>Non-Leopard users (10.4 and before): Go download <a href="http://developer.apple.com/tools/xcode/">XCode 2.5</a> from Apple's site.  Again, you may have to register as a developer.  Then, download the <a href="http://www.apple.com/support/downloads/x11formacosx.html">X11</a> package and install it, then continue with installing MacPorts below.</p>
	<!-- TODO: ensure that the x11 headers are installed	-->

<p>Next, install <a href="http://www.macports.org/">MacPorts</a> (instructions are on their site), and enter this command in Terminal:</p>
<table><tr><td>	$ sudo port install gmake</tr></td></table>
<p>You should be good to go!  Please let me know if you have any issues; I may have forgotten a step or two.

<a name="setup_linux"><h2>Setup on Linux</h2>
<p>If you've made it this far in the semester with Linux, you should have the necessary compilers and libraries needed to compile the project.  However, to ensure that you have the correct GUI libraries, you might need to install a few new packages.</p>
	<p>If you are using a Debian based distribution (like Ubuntu):</p>
	<table>
	<tr><td>  $ sudo aptitude update && sudo aptitude install build-essential libgtk2.0-dev</td></tr>
	</table>
	<p>
	If you're still getting errors, you may need to install another package.  Look at the output of "uname -a" and look for a string like "Linux 2.6.15-28-<b>686</b>". Take note of the bolded numbers (your arch) and do:
	</p>
	<table>
	<tr><td>  $ sudo aptitude install linux-headers-<b>arch</b></td></tr>
	</table>
<p>If you're on a different distribution, look in your package management system for the appropriate packages..  Email me if you have issues.</p>


<a name="setup_other"><h2>Setup on Other Machines</h2>
<p>If you're using something other than Windows, OS X or Linux, you're on your own.  Let us know if there's a problem with which we can help.</p>

</body>
</html>
